/*
 * Copyright 2010 The MyBatis Team
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mybatis.generator.codegen.mybatis3.javamapper.elements.sqlprovider;

import java.util.Set;
import java.util.TreeSet;

import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;

public class ProviderApplyWhereMethodGenerator extends AbstractJavaProviderMethodGenerator
{
    
    private static final String[] methodLines = { "if (example == null) {", //$NON-NLS-1$
                                                  "return;", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "", //$NON-NLS-1$
                                                  "String parmPhrase1;", //$NON-NLS-1$
                                                  "String parmPhrase1_th;", //$NON-NLS-1$
                                                  "String parmPhrase2;", //$NON-NLS-1$
                                                  "String parmPhrase2_th;", //$NON-NLS-1$
                                                  "String parmPhrase3;", //$NON-NLS-1$
                                                  "String parmPhrase3_th;", //$NON-NLS-1$
                                                  "if (includeExamplePhrase) {", //$NON-NLS-1$
                                                  "parmPhrase1 = \"%s #{example.oredCriteria[%d].allCriteria[%d].value}\";", //$NON-NLS-1$
                                                  "parmPhrase1_th = \"%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}\";", //$NON-NLS-1$
                                                  "parmPhrase2 = \"%s #{example.oredCriteria[%d].allCriteria[%d].value} and #{example.oredCriteria[%d].criteria[%d].secondValue}\";", //$NON-NLS-1$
                                                  "parmPhrase2_th = \"%s #{example.oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{example.oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}\";", //$NON-NLS-1$
                                                  "parmPhrase3 = \"#{example.oredCriteria[%d].allCriteria[%d].value[%d]}\";", //$NON-NLS-1$
                                                  "parmPhrase3_th = \"#{example.oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}\";", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "parmPhrase1 = \"%s #{oredCriteria[%d].allCriteria[%d].value}\";", //$NON-NLS-1$
                                                  "parmPhrase1_th = \"%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s}\";", //$NON-NLS-1$
                                                  "parmPhrase2 = \"%s #{oredCriteria[%d].allCriteria[%d].value} and #{oredCriteria[%d].criteria[%d].secondValue}\";", //$NON-NLS-1$
                                                  "parmPhrase2_th = \"%s #{oredCriteria[%d].allCriteria[%d].value,typeHandler=%s} and #{oredCriteria[%d].criteria[%d].secondValue,typeHandler=%s}\";", //$NON-NLS-1$
                                                  "parmPhrase3 = \"#{oredCriteria[%d].allCriteria[%d].value[%d]}\";", //$NON-NLS-1$
                                                  "parmPhrase3_th = \"#{oredCriteria[%d].allCriteria[%d].value[%d],typeHandler=%s}\";", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "", //$NON-NLS-1$
                                                  "StringBuilder sb = new StringBuilder();", //$NON-NLS-1$
                                                  "List<Criteria> oredCriteria = example.getOredCriteria();", //$NON-NLS-1$
                                                  "boolean firstCriteria = true;", //$NON-NLS-1$
                                                  "for (int i = 0; i < oredCriteria.size(); i++) {", //$NON-NLS-1$
                                                  "Criteria criteria = oredCriteria.get(i);", //$NON-NLS-1$
                                                  "if (criteria.isValid()) {", //$NON-NLS-1$
                                                  "if (firstCriteria) {", //$NON-NLS-1$
                                                  "firstCriteria = false;", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "sb.append(\" or \");", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "", //$NON-NLS-1$
                                                  "sb.append('(');", //$NON-NLS-1$
                                                  "List<Criterion> criterions = criteria.getAllCriteria();", //$NON-NLS-1$
                                                  "boolean firstCriterion = true;", //$NON-NLS-1$
                                                  "for (int j = 0; j < criterions.size(); j++) {", //$NON-NLS-1$
                                                  "Criterion criterion = criterions.get(j);", //$NON-NLS-1$
                                                  "if (firstCriterion) {", //$NON-NLS-1$
                                                  "firstCriterion = false;", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "sb.append(\" and \");", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "", //$NON-NLS-1$
                                                  "if (criterion.isNoValue()) {", //$NON-NLS-1$
                                                  "sb.append(criterion.getCondition());", //$NON-NLS-1$
                                                  "} else if (criterion.isSingleValue()) {", //$NON-NLS-1$
                                                  "if (criterion.getTypeHandler() == null) {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase1, criterion.getCondition(), i, j));", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase1_th, criterion.getCondition(), i, j,criterion.getTypeHandler()));", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "} else if (criterion.isBetweenValue()) {", //$NON-NLS-1$
                                                  "if (criterion.getTypeHandler() == null) {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase2, criterion.getCondition(), i, j, i, j));", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase2_th, criterion.getCondition(), i, j, criterion.getTypeHandler(), i, j, criterion.getTypeHandler()));", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "} else if (criterion.isListValue()) {", //$NON-NLS-1$
                                                  "sb.append(criterion.getCondition());", //$NON-NLS-1$
                                                  "sb.append(\" (\");", //$NON-NLS-1$
                                                  "List<?> listItems = (List<?>) criterion.getValue();", //$NON-NLS-1$
                                                  "boolean comma = false;", //$NON-NLS-1$
                                                  "for (int k = 0; k < listItems.size(); k++) {", //$NON-NLS-1$
                                                  "if (comma) {", //$NON-NLS-1$
                                                  "sb.append(\", \");", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "comma = true;", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "if (criterion.getTypeHandler() == null) {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase3, i, j, k));", //$NON-NLS-1$
                                                  "} else {", //$NON-NLS-1$
                                                  "sb.append(String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler()));", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "sb.append(')');", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "sb.append(')');", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "}", //$NON-NLS-1$
                                                  "", //$NON-NLS-1$
                                                  "if (sb.length() > 0) {", //$NON-NLS-1$
                                                  "WHERE(sb.toString());", //$NON-NLS-1$
                                                  "}" //$NON-NLS-1$
    };
    
    public ProviderApplyWhereMethodGenerator()
    {
        super();
    }
    
    @Override
    public void addClassElements(TopLevelClass topLevelClass)
    {
        Set<String> staticImports = new TreeSet<String>();
        Set<FullyQualifiedJavaType> importedTypes = new TreeSet<FullyQualifiedJavaType>();
        
        staticImports.add("org.apache.ibatis.jdbc.SqlBuilder.WHERE"); //$NON-NLS-1$
        importedTypes.add(new FullyQualifiedJavaType("java.util.List")); //$NON-NLS-1$
        
        FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(introspectedTable.getExampleType());
        importedTypes.add(fqjt);
        importedTypes.add(new FullyQualifiedJavaType(String.format("%s.Criteria", fqjt.getFullyQualifiedName()))); //$NON-NLS-1$
        importedTypes.add(new FullyQualifiedJavaType(String.format("%s.Criterion", fqjt.getFullyQualifiedName()))); //$NON-NLS-1$
        
        Method method = new Method("applyWhere"); //$NON-NLS-1$
        method.setVisibility(JavaVisibility.PROTECTED);
        method.addParameter(new Parameter(fqjt, "example")); //$NON-NLS-1$
        method
            .addParameter(new Parameter(FullyQualifiedJavaType.getBooleanPrimitiveInstance(), "includeExamplePhrase")); //$NON-NLS-1$
        
        context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);
        
        for (String methodLine : methodLines) {
            method.addBodyLine(methodLine);
        }
        
        if (context.getPlugins().providerApplyWhereMethodGenerated(method, topLevelClass, introspectedTable)) {
            topLevelClass.addStaticImports(staticImports);
            topLevelClass.addImportedTypes(importedTypes);
            topLevelClass.addMethod(method);
        }
    }
}
